﻿//--------------------------------------------------------------------------
// 
//  Copyright (c) Chili Software.  All rights reserved. 
// 
//  File: TypeMappingProviderCollection.cs
//
//  Description: Class that contains a list of type mapping providers.
// 
//--------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Chili.Opf3.Relations;

namespace Chili.Opf3.Mapping.Providers
{
	/// <summary>
	/// This class contains a list of classes that implement the <see cref="ITypeMappingProvider">ITypeMappingProvider</see>
	/// interace. These classes can create a mapping for persistent objects.
	/// </summary>
	public sealed class TypeMappingProviderCollection
	{
		private List<ITypeMappingProvider> _providers = new List<ITypeMappingProvider>();

		/// <summary>
		/// Creates a new instance of the <see cref="TypeMappingProviderCollection">TypeMappingProviderCollection Class</see>.
		/// </summary>
		internal TypeMappingProviderCollection()
		{
		}

		/// <summary>
		/// Adds a class that implements the <see cref="ITypeMappingProvider">ITypeMappingProvider</see>
		/// interface to this list.
		/// </summary>
		/// <param name="provider">The provider to add.</param>
		public void Add(ITypeMappingProvider provider)
		{
			if (provider == null)
				throw new ArgumentNullException("provider");

			if (_providers.Contains(provider))
				return;
			_providers.Add(provider);
		}

		/// <summary>
		/// Removes a class that implements the <see cref="ITypeMappingProvider">ITypeMappingProvider</see>
		/// interface from the collection.
		/// </summary>
		/// <param name="provider"></param>
		public void Remove(ITypeMappingProvider provider)
		{
			if (provider == null)
				throw new ArgumentNullException("provider");
			_providers.Remove(provider);
		}

		/// <summary>
		/// Removes all registered type mapping providers from the collection.
		/// </summary>
		public void RemoveAll()
		{
			_providers.Clear();
		}

		/// <summary>
		/// Gets the persistent attribute for the given type.
		/// </summary>
		/// <param name="type">The persistent type for which the attribute is returned.</param>
		/// <returns></returns>
		internal PersistentAttribute GetPersistentAttribute(Type type)
		{
			if (type == null)
				throw new ArgumentNullException("type");

			foreach (ITypeMappingProvider provider in _providers)
			{
				PersistentAttribute attribute = provider.GetPersistentAttribute(type);
				if (attribute != null)
					return attribute;
			}
			return null;
		}

		/// <summary>
		/// Returns the <see cref="FieldAttribute">FieldAttribute</see> for the given member. If the member is not mapped,
		/// null is returned.
		/// </summary>
		/// <param name="type">The persistent type that's mapping is created.</param>
		/// <param name="member">The member of the persistent type.</param>
		/// <returns>An instance of the <see cref="FieldAttribute">FieldAttribute</see> or null if the member is not mapped.</returns>
		internal FieldAttribute GetMemberFieldAttribute(Type type, MemberInfo member)
		{
			if (type == null)
				throw new ArgumentNullException("type");
			if (member == null)
				throw new ArgumentNullException("member");

			foreach (ITypeMappingProvider provider in _providers)
			{
				FieldAttribute attribute = provider.GetMemberFieldAttribute(type, member);
				if (attribute != null)
					return attribute;
			}
			return null;
		}

		/// <summary>
		/// Returns the <see cref="RelationAttribute">RelationAttribute</see> for the given member. If the member does not
		/// have an attribute set, null is returned.
		/// </summary>
		/// <param name="type">The persistent type that's mapping is created.</param>
		/// <param name="member">The member of the persistent type.</param>
		/// <param name="relatedType">The related object's type.</param>
		/// <returns>An instance of the <see cref="RelationAttribute">RelationAttribute</see> or null if the member does not have
		/// an attribute set.</returns>
		internal RelationAttribute GetMemberRelationAttribute(Type type, MemberInfo member, Type relatedType)
		{
			if (type == null)
				throw new ArgumentNullException("type");
			if (member == null)
				throw new ArgumentNullException("member");
			if (relatedType == null)
				throw new ArgumentNullException("relatedType");

			foreach (ITypeMappingProvider provider in _providers)
			{
				RelationAttribute attribute = provider.GetMemberRelationAttribute(type, member, relatedType);
				if (attribute != null)
					return attribute;
			}
			return null;
		}
	}
}
